package pers.bc.utils.pub;

import org.xml.sax.InputSource;

import pers.bc.utils.constant.IPubCons;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.*;

/**
 * @fileRelativePath: StringUtil.java
 * @Date: Created on 2021/8/20 14:45 <br>
 * @author: LiBencheng<br>
 * @version: 1.0<br>
 */
public final class StringUtil implements IPubCons {

	/**
	 * 过滤掉中文
	 * 
	 * @param str待过滤中文的字符串
	 * @return 过滤掉中文后字符串
	 */
	public static String filterChinese(String str) {
		// 用于返回结果
		String result = str;
		boolean flag = RegUtil.isContainChinese(str);
		if (flag) {// 包含中文
			// 用于拼接过滤中文后的字符
			StringBuffer sb = new StringBuffer();
			// 用于校验是否为中文
			boolean flag2 = false;
			// 用于临时存储单字符
			char chinese = 0;
			// 5.去除掉文件名中的中文
			// 将字符串转换成char[]
			char[] charArray = str.toCharArray();
			// 过滤到中文及中文字符
			for (int i = 0; i < charArray.length; i++) {
				chinese = charArray[i];
				flag2 = RegUtil.isChinese(chinese);
				if (!flag2) {// 不是中日韩文字及标点符号
					sb.append(chinese);
				}
			}
			result = sb.toString();
		}
		return result;
	}

	/**
	 * 过滤掉 中文 以及 a-z、A-Z、_、0-9
	 * 
	 * @param str
	 *            待过滤中文的字符串
	 * @return 过滤掉中文后字符串
	 */
	public static String filterChineseAndWord(String str) {
		// 用于返回结果
		String result = str;
		boolean flag = RegUtil.isContainChinese(str);
		if (flag) {// 包含中文
			// 用于拼接过滤中文后的字符
			StringBuffer sb = new StringBuffer();
			// 用于校验是否为中文
			boolean flag2 = false;
			// 用于校验是否为字母以及数字
			boolean flag3 = false;
			// 用于临时存储单字符
			char chinese = 0;
			// 5.去除掉文件名中的中文
			// 将字符串转换成char[]
			char[] charArray = str.toCharArray();
			// 过滤到中文及中文字符
			for (int i = 0; i < charArray.length; i++) {
				chinese = charArray[i];
				flag2 = RegUtil.isChinese(chinese);
				flag3 = RegUtil.isWord(chinese);
				if (!flag2 && !flag3) {// 不是中日韩文字及标点符号
					sb.append(chinese);
				}
			}
			result = sb.toString();
		}
		return result;
	}

	public static String reverse(Object obj) {
		if (PubEnvUtil.isEmptyObj(obj)) {
			return "";
		}
		String s = toString(obj);
		StringBuffer sb = new StringBuffer();
		Stack stack = new Stack();
		for (int i = 0; i < s.length(); i++) {
			stack.push(s.charAt(i));
		}
		// stack会返回栈顶值，并且会把该值删除
		while (!stack.isEmpty()) {
			sb.append(stack.pop());
		}

		return sb.toString();
	}

	/*************************************************************
	 * <br>
	 * 
	 * 说明:是否是xml文档 <br>
	 * 
	 * @Description <br>
	 * @Date Created on 2020/9/29 15:13 <br>
	 * @Param [rtnMsg] <br>
	 * @return boolean <br>
	 * @Author LIBENCHENG
	 * @version 1.0 <br>
	 ************************************************************* <br>
	 */
	public static boolean isXmlDocument(String rtnMsg) {
		boolean flag = true;
		try {
			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder builder = documentBuilderFactory
					.newDocumentBuilder();
			builder.parse(new InputSource(new StringReader(rtnMsg)));
		} catch (Exception e) {
			flag = false;
		}

		return flag;
	}

	/**
	 * 把中文转成Unicode码
	 * 
	 * @param str
	 * @return
	 */
	public static String chinaToUnicode(String str) {
		String result = "";
		if (PubEnvUtil.isEmpty(str)) {
			return result;
		}
		for (int i = 0; i < str.length(); i++) {
			int chr1 = (char) str.charAt(i);
			if (chr1 >= 19968 && chr1 <= 171941) {// 汉字范围 \u4e00-\u9fa5 (中文)
				result += "\\u" + Integer.toHexString(chr1);
			} else {
				result += str.charAt(i);
			}
		}
		return result;
	}

	/*************************************************************
	 * <br>
	 * 
	 * 说明:获得字符串编码 <br>
	 * 
	 * @Description <br>
	 * @Date Created on 2021/11/4 23:03 <br>
	 * @param str
	 * <br>
	 * @return java.lang.String <br>
	 * @Author LIBENCHENG
	 * @version 1.0 <br>
	 ************************************************************* <br>
	 */
	public static String getEncoding(String str) {
		String encode;

		encode = "GBK";
		try {
			if (str.equals(new String(str.getBytes(), encode))) {
				return encode;
			}
		} catch (Exception ex) {
		}

		encode = "UTF-8";
		try {
			if (str.equals(new String(str.getBytes(), encode))) {
				return encode;
			}
		} catch (Exception ex) {
		}

		encode = "GB2312";
		try {
			if (str.equals(new String(str.getBytes(), encode))) {
				return encode;
			}
		} catch (Exception ex) {
		}

		encode = "UTF-16";
		try {
			if (str.equals(new String(str.getBytes(), encode))) {
				return encode;
			}
		} catch (Exception ex) {
		}

		encode = "ASCII";
		try {
			if (str.equals(new String(str.getBytes(), encode))) {
				// "字符串<< " + str + " >>中仅由数字和英文字母组成，无法识别其编码格式"
				return null;
			}
		} catch (Exception ex) {
		}

		encode = "ISO-8859-1";
		try {
			if (str.equals(new String(str.getBytes(), encode))) {
				return encode;
			}
		} catch (Exception ex) {
		}
		/*
		 * ......待完善
		 */

		return "UTF-8";
	}

	/**
	 * *********************************************************** <br>
	 * 说明：根据身份证获取男女 <br>
	 * 
	 * @param ID
	 * @return <br>
	 * @Integer <br>
	 * @methods pers.bc.utils.pub.StringUtilbc#getSex <br>
	 * @author licheng <br>
	 * @date Created on 2020-4-10 <br>
	 * @time 下午3:20:11 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static Integer getSex(String ID) {
		if (ID.length() != 15 && ID.length() != 18) {
			return null;
		}
		int isex = 2;
		isex = ID.length() == 15 ? Integer.parseInt(ID.substring(14)) : Integer
				.parseInt(ID.substring(16, 17));
		return isex % 2 == 0 ? 2 : 1;
	}

	/**
	 * *********************************************************** <br>
	 * 说明： 获取xml格式片段<br>
	 * 
	 * @param key
	 * @param value
	 * @return { key> value /key> }<br>
	 * @String <br>
	 * @methods pers.bc.utils.pub.StringUtilbc#getXMLTypeStr <br>
	 * @author LiBencheng <br>
	 * @date Created on 2020-10-13 <br>
	 * @time 下午12:58:46 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static String getXMLTypeStr(String key, String value) {
		// return "<" + key + ">" + value + "</" + key + ">";
		// return LEFT_CHEV + key + RIGHT_CHEV + value + LEFT_CHEV + SLASH + key
		// + RIGHT_CHEV;
		return new StringBuffer().append(LEFT_CHEV).append(key)
				.append(RIGHT_CHEV).append(value).append(LEFT_CHEV)
				.append(SLASH).append(key).append(RIGHT_CHEV).toString();
	}

	/**
	 * *********************************************************** <br>
	 * 说明：获取JSON格式片段 <br>
	 * 
	 * @param key
	 * @param value
	 * @return "key":"value" <br>
	 * @String <br>
	 * @methods pers.bc.utils.pub.StringUtilbc#getJSONTypeStr <br>
	 * @author LiBencheng <br>
	 * @date Created on 2020-10-13 <br>
	 * @time 下午1:01:27 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static String getJSONTypeStr(String key, String value) {
		// return "\"" + key + "\":\"" + value + "\"";
		// QUOTE + key + QUOTE + COLON + QUOTE + value + QUOTE;
		return new StringBuffer().append(QUOTE).append(key).append(QUOTE)
				.append(COLON).append(QUOTE).append(value).append(QUOTE)
				.toString();

	}

	public static String getJSONSingleStr(String key, String value) {
		return new StringBuffer().append(LEFT_BRACE)
				.append(getJSONTypeStr(key, value)).append(RIGHT_BRACE)
				.toString();
	}

	/**
	 * *********************************************************** <br>
	 * 说明：根据身份证获取生日 <br>
	 * 
	 * @param ID
	 * @return <br>
	 * @String <br>
	 * @methods pers.bc.utils.pub.StringUtilbc#getBirthdate <br>
	 * @author licheng <br>
	 * @date Created on 2020-4-10 <br>
	 * @time 下午3:20:43 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static String getBirthdate(String ID) {
		// 不是15位或18位返回null
		if (ID.length() != 15 && ID.length() != 18) {
			return null;
		}
		String birth = ID.length() == 15 ? "19" + ID.substring(6, 12) : ID
				.substring(6, 14);
		String year = birth.substring(0, 4);
		String month = birth.substring(4, 6);
		String date = birth.substring(6);
		return year + "-" + month + "-" + date;
	}

	static final char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
			'9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
			'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
			'z' };

	private StringUtil() {
	}

	/**
	 * *********************************************************** <br>
	 * 说明：首字母小写 <br>
	 * 
	 * @param function
	 *            名称
	 * @return <br>
	 * @String <br>
	 * @methods pers.bc.utils.pub.StringUtilbc#firstCharLowerCase <br>
	 * @author licheng <br>
	 * @date Created on 2020年3月24日 <br>
	 * @time 下午8:02:49 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static String firstCharLowerCase(String function) {
		if (function.length() >= 1) {
			function = function.substring(0, 1).toLowerCase()
					+ function.substring(1);
		}
		{
			return function;
		}
	}

	/**
	 * *********************************************************** <br>
	 * 说明： 首字母大写<br>
	 * 
	 * @param function
	 *            名称
	 * @return <br>
	 * @String <br>
	 * @methods pers.bc.utils.pub.StringUtilbc#firstCharUpperCase <br>
	 * @author licheng <br>
	 * @date Created on 2020年3月24日 <br>
	 * @time 下午8:03:03 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static String firstCharUpperCase(String function) {
		if (function.length() >= 1) {
			function = function.substring(0, 1).toUpperCase()
					+ function.substring(1);
		}
		{
			return function;
		}
	}

	/**
	 * *********************************************************** <br>
	 * 说明： <br>
	 * 
	 * @param sbStr
	 * @param i
	 * @return <br>
	 * @StringBuilder <br>
	 * @methods pers.bc.utils.pub.CollectionUtil#deleteStr <br>
	 * @author LiBencheng <br>
	 * @date Created on 2020-10-17 <br>
	 * @time 上午11:03:45 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static StringBuilder deleteStr(StringBuilder sbStr, int i) {
		return sbStr.delete(sbStr.length() - i, sbStr.length());
	}

	public static String to32Signed(int i) {
		char[] buf = new char[32];
		int charPos = 32;
		int radix = 32;
		int mask = radix - 1;
		do {
			buf[(--charPos)] = digits[(i & mask)];
			i >>>= 5;
		} while (i != 0);

		String s = new String(buf, charPos, 32 - charPos);
		return s.toUpperCase();
	}

	/**
	 * *********************************************************** <br>
	 * 说明： <br>
	 * 
	 * @param obj
	 * @return <br>
	 * @String <br>
	 * @methods pers.bc.utils.pub.StringUtilbc#toString <br>
	 * @author LiBencheng <br>
	 * @date Created on 2020-11-10 <br>
	 * @time 下午5:05:52 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static String toString(Object obj) {
		String msg = null;
		try {
			msg = toString(obj, Boolean.FALSE);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}

		return msg;
	}

	public static int getSize(Collection<?> collection) {
		return (null == collection ? 0 : collection.size());
	}

	public static int getSize(Object[] objs) {
		return (null == objs ? 0 : objs.length);
	}

	public static int getSize(Map<?, ?> map) {
		return (null == map ? 0 : map.size());
	}

	public static String toString(Object obj, Boolean isPrintBean)
			throws Exception {

		if (obj == null) {
			return "null";
		}

		else if (obj instanceof String) {
			return (String) obj;
		}

		else if (obj.getClass().isArray()) {
			return toString((Object[]) obj);
		}

		else if (obj instanceof Map) {
			return toString((Map<?, ?>) obj);
		}

		else if (obj instanceof Collection) {
			return toString((Collection<?>) obj);
		}

		else if (obj instanceof Throwable) {
			return toString((Throwable) obj);
		}

		else if (obj instanceof Thread) {
			return toString(((Thread) obj).getStackTrace());
		}

		else if (isPrintBean) {
			return toString(CollectionUtil.transBean2Map(obj));
		}

		return obj.toString();
	}

	public static String toString(Object[] objs) {
		if (getSize(objs) < 1) {
			return EMPTY;
		}

		StringBuilder sb = new StringBuilder(LEFT_SQ_BRACKET);
		for (Object obj : objs) {
			sb.append(toString(obj)).append(COMMA).append(RN);
		}

		return deleteStr(sb, 3).append(RIGHT_SQ_BRACKET).toString();
	}

	public static String toString(Map<?, ?> map) {
		if (getSize(map) < 1) {
			return EMPTY;
		}
		StringBuilder sb = new StringBuilder(LEFT_BRACE);
		for (Object key : map.keySet()) {
			Object value = map.get(key);
			sb.append(toString(key)).append(EQUALS).append(toString(value))
					.append(COMMA).append(RN);
		}

		return deleteStr(sb, 3).append(RIGHT_BRACE).toString();
	}

	public static String toString(Collection<?> list) {
		if (getSize(list) < 1) {
			return EMPTY;
		}

		StringBuilder sb = new StringBuilder(LEFT_SQ_BRACKET);
		for (Object e : list) {
			sb.append(toString(e)).append(COMMA).append(RN);
		}

		return deleteStr(sb, 3).append(RIGHT_SQ_BRACKET).toString();
	}

	public static String toString(Throwable e) {
		if (e == null) {
			return EMPTY;
		}

		StringBuilder log = new StringBuilder();
		int count = 0;
		while ((e != null) && (count < 50)) {
			count++;
			log.append(e.toString()).append(RN);
			StackTraceElement[] trace = e.getStackTrace();
			for (int i = 0; i < trace.length; i++) {
				log.append("      at ").append(trace[i]).append(RN);
			}

			e = e.getCause();
		}
		return log.toString();
	}

	public static String subString(String input, int len) {
		if ((input == null) || (input.length() * 2 < len)) {
			return input;
		}
		StringBuffer sb = new StringBuffer(len);
		int count = 0;
		for (int i = 0; i < input.length(); i++) {
			char c = input.charAt(i);
			if (c <= '?') {
				count++;
			} else {
				count += 2;
			}
			if (count > len) {
				return sb.toString();
			}

			sb.append(c);
		}
		return sb.toString();
	}

	public static String arr2Str(Object[] objs, String regex) {
		if ((objs == null) || (objs.length < 1)) {
			return null;
		}
		StringBuffer bf = new StringBuffer();
		for (Object obj : objs) {
			bf.append(regex).append(obj);
		}

		return bf.substring(regex.length());
	}

	public static String stringTrimRight(String strValue) {
		if (strValue == null) {
			return strValue;
		}
		int count = strValue.length();
		int len = strValue.length();
		int off = 0;
		char[] val = strValue.toCharArray();

		while (val[(off + len - 1)] <= ' ') {
			len--;
		}
		return len < count ? strValue.substring(0, len) : strValue;
	}

	/**
	 * *********************************************************** <br>
	 * 说明：去掉字符串中的常用符号 <br>
	 * 
	 * @param str
	 * @param newChar
	 * @return <br>
	 * @String <br>
	 * @methods pers.bc.utils.pub.StringUtilbc#replaceCharSpecial <br>
	 * @author LiBencheng <br>
	 * @date Created on 2020-12-17 <br>
	 * @time 下午3:48:28 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static String replaceCharSpecial(String str, CharSequence newChar) {
		List<String> specials = new ArrayList<String>();

		char[] charArray = (HXWFHS + MATH_SYMBOL).toCharArray();
		for (int i = 0, j = charArray.length; i < j; i++) {
			specials.add(String.valueOf(charArray[i]));
		}

		specials.add("（");
		specials.add("）");
		specials.add(LEFT_BRACKET);
		specials.add(RIGHT_BRACKET);
		specials.add(CRLF);
		specials.add(TAB);
		specials.add(RETURN);
		specials.add(NEWLINE);
		specials.add(HTML_NBSP);
		specials.add(HTML_AMP);
		specials.add(HTML_QUOTE);
		specials.add(HTML_LT);
		specials.add(HTML_GT);

		String newStr = replaceChar(str, specials.toArray(new String[0]),
				newChar);

		return newStr;
	}

	/**
	 * *********************************************************** <br>
	 * 说明：把字符串中去掉将指定的字符 <br>
	 * 
	 * @param str
	 * @param oldChars
	 * @param newChar
	 * @return <br>
	 * @String <br>
	 * @methods pers.bc.utils.pub.StringUtilbc#replaceChar <br>
	 * @author LiBencheng <br>
	 * @date Created on 2020-12-17 <br>
	 * @time 下午3:48:54 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static String replaceChar(String str, CharSequence[] oldChars,
			CharSequence newChar) {
		String newStr = str;
		for (int i = 16, j = getSize(oldChars); i < j; i++) {
			newStr = newStr.replace(oldChars[i], newChar);
			// str.replaceAll(StringUtilbc.valueOf(oldChars[getDecryptObjSize(i)]),
			// StringUtilbc.valueOf(newChar));
		}

		return newStr;
	}

	public static String replace(String text, String repl, String with) {
		return replace(text, repl, with, -1);
	}

	public static String replace(String text, String repl, String with, int max) {
		if ((text == null) || (PubEnvUtil.isEmpty(repl)) || (with == null)
				|| (max == 0)) {
			return text;
		}

		StringBuffer buf = new StringBuffer(text.length());
		int start = 0;
		int end = 0;
		for (; (end = text.indexOf(repl, start)) != -1;) {
			buf.append(text.substring(start, end)).append(with);
			start = end + repl.length();
			max--;
		}

		buf.append(text.substring(start));
		return buf.toString();
	}

	public static final String innerText(String html) {
		if (((html) == null) || ("".equals((html)))) {
			return html;
		}

		String value = html;
		int nEnd = 0;
		int nStart;
		while ((nStart = value.indexOf("<")) >= 0) {
			nEnd = value.indexOf(">", nStart);
			if (nEnd <= nStart) {
				break;
			}
			value = value.substring(0, nStart) + value.substring(nEnd + 1);
		}

		return value;
	}

	public static String capitalize(String str) {
		int strLen;

		if ((str == null) || ((strLen = str.length()) == 0)) {
			return str;
		}

		return strLen + Character.toTitleCase(str.charAt(0)) + str.substring(1);
	}

	public static String[] addStringToArray(String[] array, String str) {
		if (array == null) {
			return new String[] { str };
		}

		String[] newArr = new String[array.length + 1];
		System.arraycopy(array, 0, newArr, 0, array.length);
		newArr[array.length] = str;
		return newArr;
	}

	public static String[] extractArrayFromIn(String in) {
		if ((in == null) || (in.trim().length() == 0)) {
			return new String[0];
		}
		if (in.startsWith("(")) {
			in = in.substring(1, in.length());
		}
		if (in.endsWith(")")) {
			in = in.substring(0, in.length() - 1);
		}
		String[] result = in.split(",");
		ArrayList<String> results = new ArrayList<String>();
		for (String s : result) {
			s = s.trim();
			if (s.startsWith("'")) {
				s = s.substring(1, s.length());
			}
			if (s.endsWith("'")) {
				s = s.substring(0, s.length() - 1);
			}
			if (s.startsWith("\"")) {
				s = s.substring(1, s.length());
			}
			if (s.endsWith("\"")) {
				s = s.substring(0, s.length() - 1);
			}

			results.add(s);
		}
		return (String[]) results.toArray(new String[0]);
	}

	/**
	 * *********************************************************** <br>
	 * 说明： <br>
	 * 
	 * @param sttrs
	 * @return <br>
	 * @String <br>
	 * @methods nc.pub.itf.tools.pub.StringUtilbc#convert2String <br>
	 * @author licheng <br>
	 * @date Created on 2019-8-12 <br>
	 * @time 上午11:05:54 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static String convert2String(List<String> sttrs) {
		StringBuffer newStr = new StringBuffer();
		int len = sttrs.size();
		for (int i = 0; i < len; i++) {
			newStr.append((String) sttrs.get(i));
			if (i != len - 1) {
				newStr.append(",");
			}
		}

		return newStr.toString();
	}

	public static String convert2String(List<String> sttrs, boolean bChar) {
		StringBuffer newStr = new StringBuffer();
		int len = sttrs.size();
		for (int i = 0; i < len; i++) {
			if (bChar) {
				newStr.append("'");
			}
			newStr.append((String) sttrs.get(i));
			if (bChar) {
				newStr.append("'");
			}
			if (i != len - 1) {
				newStr.append(",");
			}
		}

		return newStr.toString();
	}

	public static boolean containsChinese(String str) {
		if (PubEnvUtil.isEmpty(str)) {
			return false;
		}
		for (int i = 0; i < str.length(); i++) {
			String c = str.charAt(i) + "";
			if (c.matches("[\\u4E00-\\u9FA5]+")) {
				return true;
			}
		}
		return false;
	}

	public static boolean isNotBlank(CharSequence cs) {
		return !isBlank(cs);
	}

	/**
	 * *********************************************************** <br>
	 * 说明： *
	 * 
	 * <pre>
	 * StringUtils.isBlank(null)      = true
	 * StringUtils.isBlank("")        = true
	 * StringUtils.isBlank(" ")       = true
	 * StringUtils.isBlank("bob")     = false
	 * StringUtils.isBlank("  bob  ") = false
	 * </pre>
	 * 
	 * <br>
	 * 
	 * @param cs
	 * @return <br>
	 * @boolean <br>
	 * @methods pers.bc.utils.pub.StringUtil#isBlank <br>
	 * @author LiBencheng <br>
	 * @date Created on 2020-11-19 <br>
	 * @time 14:28:00 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static boolean isBlank(final CharSequence cs) {
		int strLen;
		if (cs == null || (strLen = cs.length()) == 0) {
			return true;
		}
		for (int i = 0; i < strLen; i++) {
			if (!Character.isWhitespace(cs.charAt(i))) {
				return false;
			}
		}
		return true;
	}

	public static final String replaceAll(String tmpl, String src, String desc) {
		StringBuffer buf = new StringBuffer();
		int index = tmpl.indexOf(src);
		int len = src.length();
		while (index >= 0) {
			buf.append(tmpl.substring(0, index));
			buf.append(desc);
			tmpl = tmpl.substring(index + len);
			index = tmpl.indexOf(src);
		}
		buf.append(tmpl);
		return buf.toString();
	}

	public static boolean isMultiLangResID(String resId) {
		if ((resId == null) || (resId.length() < 6)) {
			return false;
		}

		if ((resId.contains("@")) && (!resId.startsWith("@"))
				&& (!resId.endsWith("@"))) {
			return true;
		}

		if (containsChinese(resId)) {
			return false;
		}

		return true;
	}

	public static String getFuncCodeFromResID(String resId) {
		if ((resId == null) || (resId.length() < 6)) {
			return null;
		}

		if ((resId.contains("@")) && (!resId.startsWith("@"))
				&& (!resId.endsWith("@"))) {
			return resId.split("@")[1];
		}

		int endIndex = 1;
		for (int i = resId.length() - 1; i > 1; i--) {
			char c = resId.charAt(i);
			if (c == '-') {
				endIndex = i - 1;
				break;
			}
		}

		if (endIndex < 2) {
			endIndex = resId.length() - 5;
		}

		String funcCode = resId.substring(1, endIndex + 1);
		return funcCode;
	}

	/**
	 * Returns the string representation of the <code>Object</code> argument.
	 * 
	 * @param obj
	 *            an <code>Object</code>.
	 * @return if the argument is <code>null</code>, then a string equal to
	 *         <code>"null"</code>; otherwise, the value of
	 *         <code>obj.toString()</code> is returned.
	 * @see Object#toString()
	 */
	public static String valueOf(Object obj) {
		return (null == obj) ? null : toString(setObj(obj));
	}

	/**
	 * *********************************************************** <br>
	 * 说明：为空时默认为0 <br>
	 * 
	 * @param obj
	 * @return <br>
	 * @String <br>
	 * @methods pers.bc.utils.pub.StringUtilbc#valueOfZero <br>
	 * @author LiBencheng <br>
	 * @date Created on 2020-11-7 <br>
	 * @time 下午11:39:00 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static String valueOfZero(Object obj) {
		return valueOfDefault(obj, ZERO);
	}

	public static String valueOfDefault(Object obj, String defValue) {
		return (valueOfEmpty(obj).length() < 1) ? valueOfEmpty(defValue)
				: toString(obj);
	}

	/**
	 * *********************************************************** <br>
	 * 说明： <br>
	 * 
	 * @param obj
	 * @return <br>
	 * @String <br>
	 * @methods nc.pub.itf.tools.pub.StringUtilbc#valueOfEmpty <br>
	 * @author licheng <br>
	 * @date Created on 2019-9-24 <br>
	 * @time 下午5:43:37 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static String valueOfEmpty(Object obj) {
		return (null == obj) ? "" : toString(setObj(obj));
	}

	/**
	 * *********************************************************** <br>
	 * 说明： <br>
	 * 
	 * @param obj
	 * @return <br>
	 * @String <br>
	 * @methods nc.pub.itf.tools.pub.StringUtilbc#valueOfNull <br>
	 * @author licheng <br>
	 * @date Created on 2019-9-24 <br>
	 * @time 下午5:43:33 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static String valueOfNull(Object obj) {
		return String.valueOf(setObj(obj));
	}

	private static Object setObj(Object obj) {
		if ((null == obj))
			return obj;
		if (obj instanceof BigDecimal) {
			obj = Double.valueOf(((BigDecimal) obj).doubleValue()).isNaN() ? ZERO
					: obj;
		}
		if (obj instanceof Double) {
			obj = ((Double) obj).isNaN() ? Double.valueOf(ZERO) : obj;
		}

		return obj;
	}

	/**
	 * *********************************************************** <br>
	 * 说明： <br>
	 * 
	 * @param str
	 * @return <br>
	 * @String <br>
	 * @methods pers.bc.utils.pub.StringUtilbc#deleteWhitespace <br>
	 * @author licheng <br>
	 * @date Created on 2019-12-19 <br>
	 * @time 下午2:36:24 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	public static String deleteWhitespace(String str) {
		if (PubEnvUtil.isEmpty(str)) {
			return str;
		}

		int sz = str.length();
		char[] chs = new char[sz];
		int count = 0;
		for (int i = 0; i < sz; i++) {
			if (!Character.isWhitespace(str.charAt(i))) {
				chs[count++] = str.charAt(i);
			}
		}
		if (count == sz) {
			return str;
		}

		return new String(chs, 0, count);
	}

	/**
	 * *********************************************************** <br>
	 * 说明： <br>
	 * 第一种实现方式
	 * 
	 * @param strA
	 * @param strB
	 * @return <br>
	 * @String <br>
	 * @methods nc.pub.itf.tools.pub.StringImpl#longestCommonSubstring <br>
	 * @author licheng <br>
	 * @date Created on 2019-8-12 <br>
	 * @time 上午10:23:24 <br>
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see <br>
	 */
	private static String longestCommonSubstring(String strA, String strB) {
		char[] chars_strA = strA.toCharArray();
		char[] chars_strB = strB.toCharArray();
		int m = chars_strA.length;
		int n = chars_strB.length;
		int[][] matrix = new int[m + 1][n + 1];
		for (int i = 1; i <= m; i++) {
			for (int j = 1; j <= n; j++) {
				if (chars_strA[i - 1] == chars_strB[j - 1]) {
					matrix[i][j] = matrix[i - 1][j - 1] + 1;
				} else {
					matrix[i][j] = Math.max(matrix[i][j - 1], matrix[i - 1][j]);
				}
			}
		}
		char[] result = new char[matrix[m][n]];
		int currentIndex = result.length - 1;
		while (matrix[m][n] != 0) {
			if (matrix[n] == matrix[n - 1]) {
				n--;
			} else if (matrix[m][n] == matrix[m - 1][n]) {
				m--;
			} else {
				result[currentIndex] = chars_strA[m - 1];
				currentIndex--;
				n--;
				m--;
			}
		}

		return new String(result);
	}

	/**
	 * *********************************************************** <br>
	 * 说明：
	 * 
	 * @param charValue
	 * @return
	 * @boolean
	 * @author licheng
	 * @date Created on 2019-7-24
	 * @time 下午6:44:54
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see
	 */
	private static boolean charReg(char charValue) {
		return (charValue >= 0x4E00 && charValue <= 0X9FA5)
				|| (charValue >= 'a' && charValue <= 'z')
				|| (charValue >= 'A' && charValue <= 'Z')
				|| (charValue >= '0' && charValue <= '9');
	}

	/**
	 * *********************************************************** <br>
	 * 说明：
	 * 
	 * @param str
	 * @return
	 * @String
	 * @author licheng
	 * @date Created on 2019-7-24
	 * @time 下午6:45:01
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see
	 */
	private static String removeSign(String str) {
		StringBuffer sb = new StringBuffer();
		for (char item : str.toCharArray()) {
			if (charReg(item)) {
				sb.append(item);
			}
		}

		return sb.toString();
	}

	/**
	 * 快速比较俩个字符串的相似度
	 * 
	 * @param strL
	 *            较长的字符串
	 * @param strS
	 *            较短的字符串
	 * @return 俩个字符串的相似度
	 *         <p>
	 *         summary
	 *         </p>
	 *         :较长的字符串放到前面有助于提交效率
	 */
	public static double SimilarDegree(String strL, String strS) {
		String newStrA = removeSign(strL);
		String newStrB = removeSign(strS);
		int temp = Math.max(newStrA.length(), newStrB.length());
		int temp2 = longestCommonSubstring(newStrA, newStrB).length();
		return temp2 * 1.0 / temp;
	}

	// 第二种实现方式
	private static int compare(String str, String target) {
		int d[][]; // 矩阵
		int n = str.length();
		int m = target.length();
		int i; // 遍历str的
		int j; // 遍历target的
		char ch1; // str的
		char ch2; // target的
		int temp; // 记录相同字符,在某个矩阵位置值的增量,不是0就是1
		if (n == 0) {
			return m;
		}
		if (m == 0) {
			return n;
		}
		d = new int[n + 1][m + 1];
		// 初始化第一列
		for (i = 0; i <= n; i++) {
			d[i][0] = i;
		}
		// 初始化第一行
		for (j = 0; j <= m; j++) {
			d[0][j] = j;
		}

		for (i = 1; i <= n; i++) { // 遍历str
			ch1 = str.charAt(i - 1);
			// 去匹配target
			for (j = 1; j <= m; j++) {
				ch2 = target.charAt(j - 1);
				if (ch1 == ch2) {
					temp = 0;
				} else {
					temp = 1;
				}

				// 左边+1,上边+1, 左上角+temp取最小
				d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1]
						+ temp);
			}
		}
		return d[n][m];
	}

	/**
	 * *********************************************************** <br>
	 * 说明：
	 * 
	 * @param one
	 * @param two
	 * @param three
	 * @return
	 * @int
	 * @author licheng
	 * @date Created on 2019-7-24
	 * @time 下午7:29:49
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see
	 */
	private static int min(int one, int two, int three) {
		return (one = one < two ? one : two) < three ? one : three;
	}

	/**
	 * *********************************************************** <br>
	 * 说明： 获取字符串的相似度
	 * 
	 * @param str
	 * @param target
	 * @return
	 * @double
	 * @author licheng
	 * @date Created on 2019-7-24
	 * @time 下午6:45:59
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see
	 */
	public static double SimilarityRatio(String str, String target) {
		return 1 - (double) compare(str, target)
				/ Math.max(str.length(), target.length());
	}

	/**
	 * *********************************************************** <br>
	 * 说明： 获取字符串编码
	 * 
	 * @param str
	 *            需要处理的字符串
	 * @return
	 * @String
	 * @author licheng
	 * @date Created on 2019-7-24
	 * @time 下午6:46:09
	 * @version 1.0 <br>
	 *          ************************************************************ <br>
	 * @see
	 */
	public static String simpleEncoding(String str) {
		try {
			byte[] bs = str.getBytes(System.getProperty("file.encoding"));
			if (str.equals(new String(bs, UTF_8))) {
				return UTF_8;
			}
			if (str.equals(new String(bs, GBK))) {
				return GBK;
			}
			if (str.equals(new String(bs, ISO_8859_1))) {
				return ISO_8859_1;
			}
			if (str.equals(new String(str.getBytes(GB2312), GB2312))) {
				return GB2312;
			}
			if (str.equals(new String(str.getBytes(ISO_8859_1), ISO_8859_1))) {
				return ISO_8859_1;
			}
			if (str.equals(new String(str.getBytes(UTF_8), UTF_8))) {
				return UTF_8;
			}
			if (str.equals(new String(str.getBytes(GBK), GBK))) {
				return GBK;
			}
		} catch (UnsupportedEncodingException exception1) {
			exception1.printStackTrace();
		}

		return "";
	}

	/**
	 * 字符串相似度比较(速度较快)
	 */
	public static double SimilarityRatioUnPunct(String str1, String str2) {
		str1 = trimPunct(str1);
		str2 = trimPunct(str2);
		if (str1.length() > str2.length()) {
			return SimilarityRatio(str1, str2);
		} else {
			return SimilarityRatio(str2, str1);
		}

	}

	/**
	 * 字符串相似度比较(速度较快)
	 */
	public static double SimilarDegreeUnPunct(String str1, String str2) {
		str1 = trimPunct(str1);
		str2 = trimPunct(str2);
		if (str1.length() > str2.length()) {
			return SimilarDegree(str1, str2);
		} else {
			return SimilarDegree(str2, str1);
		}
	}

	/**
	 * 删除所有的标点符号
	 * 
	 * @param str
	 *            处理的字符串
	 */
	public static String trimPunct(String str) {
		if (PubEnvUtil.isEmpty(str)) {
			return "";
		}
		return str.replaceAll("[\\pP\\p{Punct}]", "");
	}

	public static void main3(String[] args) {
		Date date = new Date();
		// b的使用，月份简称
		String str = String.format(Locale.US, "英文月份简称：%tb", date);
		System.out.println(str);
		System.out.printf("本地月份简称：%tb%n", date);
		// B的使用，月份全称
		str = String.format(Locale.US, "英文月份全称：%tB", date);
		System.out.println(str);
		System.out.printf("本地月份全称：%tB%n", date);
		// a的使用，星期简称
		str = String.format(Locale.US, "英文星期的简称：%ta", date);
		System.out.println(str);
		// A的使用，星期全称
		System.out.printf("本地星期的简称：%tA%n", date);
		// C的使用，年前两位
		System.out.printf("年的前两位数字（不足两位前面补0）：%tC%n", date);
		// y的使用，年后两位
		System.out.printf("年的后两位数字（不足两位前面补0）：%ty%n", date);
		// j的使用，一年的天数
		System.out.printf("一年中的天数（即年的第几天）：%tj%n", date);
		// m的使用，月份
		System.out.printf("两位数字的月份（不足两位前面补0）：%tm%n", date);
		// d的使用，日（二位，不够补零）
		System.out.printf("两位数字的日（不足两位前面补0）：%td%n", date);
		// e的使用，日（一位不补零）
		System.out.printf("月份的日（前面不补0）：%te", date);

		// c的使用
		System.out.printf("全部日期和时间信息：%tc%n", date);
		// f的使用
		System.out.printf("年-月-日格式：%tF%n", date);
		// d的使用
		System.out.printf("月/日/年格式：%tD%n", date);
		// r的使用
		System.out.printf("HH:MM:SS PM格式（12时制）：%tr%n", date);
		// t的使用
		System.out.printf("HH:MM:SS格式（24时制）：%tT%n", date);
		// R的使用
		System.out.printf("HH:MM格式（24时制）：%tR", date);

		// //////////////////////////////////////////////////////////////////////////////
		// H的使用
		System.out.printf("2位数字24时制的小时（不足2位前面补0）:%tH%n", date);
		// I的使用
		System.out.printf("2位数字12时制的小时（不足2位前面补0）:%tI%n", date);
		// k的使用
		System.out.printf("2位数字24时制的小时（前面不补0）:%tk%n", date);
		// l的使用
		System.out.printf("2位数字12时制的小时（前面不补0）:%tl%n", date);
		// M的使用
		System.out.printf("2位数字的分钟（不足2位前面补0）:%tM%n", date);
		// S的使用
		System.out.printf("2位数字的秒（不足2位前面补0）:%tS%n", date);
		// L的使用
		System.out.printf("3位数字的毫秒（不足3位前面补0）:%tL%n", date);
		// N的使用
		System.out.printf("9位数字的毫秒数（不足9位前面补0）:%tN%n", date);
		// p的使用
		str = String.format(Locale.US, "小写字母的上午或下午标记(英)：%tp", date);
		System.out.println(str);
		System.out.printf("小写字母的上午或下午标记（中）：%tp%n", date);
		// z的使用
		System.out.printf("相对于GMT的RFC822时区的偏移量:%tz%n", date);
		// Z的使用
		System.out.printf("时区缩写字符串:%tZ%n", date);
		// s的使用
		System.out.printf("1970-1-1 00:00:00 到现在所经过的秒数：%ts%n", date);
		// Q的使用
		System.out.printf("1970-1-1 00:00:00 到现在所经过的毫秒数：%tQ%n", date);

		// //////////////////////////////////////////////////////////////////////////////
		str = String.format("Hi,%s", "王力");
		System.out.println(str);
		str = String.format("Hi,%s:%s.%s", "王南", "王力", "王张");
		System.out.println(str);
		System.out.printf("字母a的大写是：%c %n", 'A');
		System.out.printf("3>7的结果是：%b %n", 3 > 7);
		System.out.printf("100的一半是：%d %n", 100 / 2);
		System.out.printf("100的16进制数是：%x %n", 100);
		System.out.printf("100的8进制数是：%o %n", 100);
		System.out.printf("50元的书打8.5折扣是：%f 元%n", 50 * 0.85);
		System.out.printf("上面价格的16进制数是：%a %n", 50 * 0.85);
		System.out.printf("上面价格的指数表示：%e %n", 50 * 0.85);
		System.out.printf("上面价格的指数和浮点数结果的长度较短的是：%g %n", 50 * 0.85);
		System.out.printf("上面的折扣是%d%% %n", 85);
		System.out.printf("字母A的散列码是：%h %n", 'A');

		// //////////////////////////////////////////////////////////////////////////////
		// $使用
		str = String.format("格式参数$的使用：%1$d,%2$s", 99, "abc");
		System.out.println(str);
		// +使用
		System.out.printf("显示正负数的符号：%+d与%d%n", 99, -99);
		// 补O使用
		System.out.printf("最牛的编号是：%03d%n", 7);
		// 空格使用
		System.out.printf("Tab键的效果是：% 8d%n", 7);
		// .使用
		System.out.printf("整数分组的效果是：%,d%n", 9989997);
		// 空格和小数点后面个数
		System.out.printf("一本书的价格是：% 50.5f元%n", 49.8);
	}
}
